home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / board / Chaos53src.lha / chaos / src / Pairings.c < prev    next >
C/C++ Source or Header  |  1994-12-03  |  35KB  |  1,469 lines

  1. /*  Chaos:            The Chess HAppening Organisation System    V5.3
  2.     Copyright (C)   1993    Jochen Wiedmann
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 2 of the License, or
  7.     (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.  
  19.     $RCSfile: Pairings.c,v $
  20.     $Revision: 3.3 $
  21.     $Date: 1994/12/03 18:02:26 $
  22.  
  23.     This file contains the pairing-functions. The algorithm of the
  24.     swiss-pairing is described in the function LoseGroup().
  25.  
  26.     Computer:    Amiga 1200            Compiler:    Dice 2.07.54 (3.0)
  27.  
  28.     Author:    Jochen Wiedmann
  29.         Am Eisteich 9
  30.       72555 Metzingen
  31.         Tel. 07123 / 14881
  32.         Internet: wiedmann@mailserv.zdv.uni-tuebingen.de
  33. */
  34.  
  35.  
  36. #ifndef CHAOS_H
  37. #include "chaos.h"
  38. #endif
  39.  
  40.  
  41.  
  42.  
  43. /*
  44.     This structure is used to build the groups of players with same numbers
  45.     of points.
  46. */
  47. struct Group
  48. { struct Group *Next;
  49.   struct Player *First;
  50.   struct Player *Last;
  51.   int NumMembers;
  52.   int NumAllocMembers;
  53. };
  54.  
  55.  
  56.  
  57. /*
  58.     Some functions to administrate a double-linked-list. They are close
  59.     to the corresponding Exec-functions.
  60. */
  61. /*
  62.     MyRemove() removes player t from group g.
  63. */
  64. void MyRemove(struct Group *g, struct Player *t)
  65.  
  66. {
  67.   if (t->LT_Pred == NULL)
  68.   { g->First = t->LT_Succ;
  69.   }
  70.   else
  71.   { t->LT_Pred->LT_Succ = t->LT_Succ;
  72.   }
  73.   if (t->LT_Succ == NULL)
  74.   { g->Last = t->LT_Pred;
  75.   }
  76.   else
  77.   { t->LT_Succ->LT_Pred = t->LT_Pred;
  78.   }
  79.   g->NumMembers--;
  80. }
  81.  
  82.  
  83.  
  84.  
  85. /*
  86.     MyAddTail() adds player t to the tail of group g.
  87. */
  88. void MyAddTail(struct Group *g, struct Player *t)
  89.  
  90. { if ((t->LT_Pred = g->Last)  ==  NULL)
  91.   { g->First = t;
  92.   }
  93.   else
  94.   { g->Last->LT_Succ = t;
  95.   }
  96.   t->LT_Succ = NULL;
  97.   g->Last = t;
  98.   g->NumMembers++;
  99. }
  100.  
  101.  
  102.  
  103.  
  104. /*
  105.     MyAddHead() adds player t to the head of group g.
  106. */
  107. void MyAddHead(struct Group *g, struct Player *t)
  108.  
  109. { if ((t->LT_Succ = g->First)  ==  NULL)
  110.   { g->Last = t;
  111.   }
  112.   else
  113.   { g->First->LT_Pred = t;
  114.   }
  115.   t->LT_Pred = NULL;
  116.   g->First = t;
  117.   g->NumMembers++;
  118. }
  119.  
  120.  
  121.  
  122.  
  123. /*
  124.     MyInsert() inserts player t into group g after player pred.
  125.     Note, that pred may be null, in which case MyAddHead() is called.
  126. */
  127. void MyInsert(struct Group *g, struct Player *t, struct Player *pred)
  128.  
  129. { if (pred == NULL)
  130.   { MyAddHead(g, t);
  131.   }
  132.   else
  133.   { if (pred->LT_Succ == NULL)
  134.     { MyAddTail(g, t);
  135.     }
  136.     else
  137.     { t->LT_Succ = pred->LT_Succ;
  138.       t->LT_Pred = pred;
  139.       pred->LT_Succ->LT_Pred = t;
  140.       pred->LT_Succ = t;
  141.       g->NumMembers++;
  142.     }
  143.   }
  144. }
  145.  
  146.  
  147.  
  148.  
  149. /*
  150.     MyEnqueue() inserts player t into group g. The group is sorted by the
  151.     player->Nr fields.
  152. */
  153. void MyEnqueue(struct Group *g, struct Player *t)
  154.  
  155. { struct Player *succ;
  156.  
  157.   for (succ = g->First;  succ != NULL;  succ = succ->LT_Succ)
  158.   { if (t->Nr < succ->Nr)
  159.     { break;
  160.     }
  161.   }
  162.   if (succ == NULL)
  163.   { MyAddTail(g, t);
  164.   }
  165.   else
  166.   { MyInsert(g, t, succ->LT_Pred);
  167.   }
  168. }
  169.  
  170.  
  171.  
  172. /*
  173.     GameAddress() returns the address of a game-structure.
  174.  
  175.     Inputs: t - player, whose game list will be searched
  176.         r - number of the round, which's game structure will be
  177.         returned. This may be 0, in which case the address of
  178.         t->First_Game will be returned.
  179.  
  180.     Result: pointer to the game structure corresponding to player t, round r
  181. */
  182. struct Game *GameAddress(struct Player *t, int r)
  183.  
  184. { struct Game *g;
  185.  
  186.   for (g = (struct Game *) &(t->First_Game);  r != 0;
  187.        g = g->Next, r--)
  188.   {
  189.   }
  190.   return(g);
  191. }
  192.  
  193.  
  194.  
  195. /*
  196.     The NewGames() function gets called after each round that has been
  197.     paired. It assumes, that each players Opponent, GFlags and BoardNr fields
  198.     are initialized.
  199.  
  200.     Inputs: memlistptr - pointer to the memory list, where the allocated
  201.              memory will be included.
  202.         fpoints    - number of points, that free players will receive
  203.              (2 for swiss pairing, 0 for round robin)
  204.  
  205.     Result: TRUE, if successful, FALSE otherwise
  206. */
  207. static int NewGames(void **memlistptr, int fpoints)
  208.  
  209. { struct Game *g, *gmem;
  210.   struct Player *t;
  211.   int NumGames = 0;
  212.  
  213.   /*
  214.       Allocate new game structures.
  215.   */
  216.   if ((gmem = GetMem(memlistptr, sizeof(*g)*NumPlayers))  ==  NULL)
  217.   { return(FALSE);
  218.   }
  219.   NumRounds++;
  220.  
  221.   /*
  222.       Initialize the game structures.
  223.   */
  224.   for (t = ((struct Player *) PlayerList.lh_Head), g = gmem;
  225.        t->Tn_Node.ln_Succ != NULL;
  226.        t = (struct Player *) t->Tn_Node.ln_Succ, g++)
  227.   { if (t->Flags & TNFLAGSF_WITHDRAWN)
  228.     { t->GFlags |= GMFLAGSF_NOFIGHT;
  229.     }
  230.     else if (t->Opponent == NULL)
  231.     { t->GFlags |= GMFLAGSF_NOFIGHT|GMFLAGSF_POINTFORFREE;
  232.     }
  233.  
  234.     GameAddress(t, NumRounds-1)->Next = g;
  235.  
  236.     g->Next = NULL;
  237.     g->Opponent = t->Opponent;
  238.     g->Flags = t->GFlags;
  239.     g->BoardNr = t->BoardNr;
  240.  
  241.     if (g->Flags & GMFLAGSF_NOFIGHT)
  242.     { if (t->Flags & TNFLAGSF_WITHDRAWN)
  243.       { g->Result = 0;
  244.     g->Flags = GMFLAGSF_WITHDRAWN;
  245.       }
  246.       else
  247.       { t->Points += fpoints;
  248.     g->Result = fpoints;
  249.     t->Flags |= TNFLAGSF_HADFREE;
  250.       }
  251.     }
  252.     else
  253.     { NumGames++;
  254.       g->Result = -1;
  255.       if (g->Flags & GMFLAGSF_WHITE)
  256.       { t->HowMuchWhite++;
  257.     if (t->HowMuchWhiteLast > 0)
  258.     { t->HowMuchWhiteLast++;
  259.     }
  260.     else
  261.     { t->HowMuchWhiteLast = 1;
  262.     }
  263.       }
  264.       else
  265.       { t->HowMuchWhite--;
  266.     if (t->HowMuchWhiteLast < 0)
  267.     { t->HowMuchWhiteLast--;
  268.     }
  269.     else
  270.     { t->HowMuchWhiteLast = -1;
  271.     }
  272.       }
  273.     }
  274.   }
  275.  
  276.   NumGamesMissing = NumGames/2;
  277.   return(TRUE);;
  278. }
  279.  
  280.  
  281.  
  282.  
  283. /*
  284.     The function CreateRankings() creates the internal ranking list.
  285.     The list is sorted by ELO numbers (if players have one) and by DWZ
  286.     numbers otherwise.
  287.     Players without rating number will appear at the tail of the list
  288. */
  289. void CreateRankings(void)
  290.  
  291. { struct Player *t, **tptr;
  292.   int t1, t2;
  293.  
  294.   RankingFirst = NULL;
  295.   for (t = (struct Player *) PlayerList.lh_Head;
  296.        t->Tn_Node.ln_Succ != NULL;
  297.        t = (struct Player *) t->Tn_Node.ln_Succ)
  298.   { /*
  299.     Get the curremt players (t) rating number into t1.
  300.     */
  301.     if ((t1 = t->ELO)  ==  0)
  302.     { t1 = tdwz(t);
  303.     }
  304.  
  305.     /*
  306.     Insert t into the internal ranking list
  307.     */
  308.     for (tptr = &RankingFirst;  *tptr != NULL;
  309.      tptr = &((*tptr)->RankNext))
  310.     { if (t1 != 0)
  311.       { if ((t2 = (*tptr)->ELO)  ==  0)
  312.     { t2 = tdwz(*tptr);
  313.     }
  314.     if (t1 > t2)
  315.     { break;
  316.     }
  317.       }
  318.     }
  319.  
  320.     t->RankNext = *tptr;
  321.     *tptr = t;
  322.   }
  323. }
  324.  
  325.  
  326.  
  327.  
  328. /*
  329.     DoSwissPairingFirst() makes the pairings of the first round of a
  330.     Swiss pairing tournament.
  331.  
  332.     Inputs: user - True, if the user may set games
  333. */
  334. static int DoSwissPairingFirst(int user)
  335.  
  336. { struct Player *t, *thelp;
  337.   int NumGames, NumFreePlayers;
  338.   int i, j;
  339.   int flag;
  340.   int BoardNr;
  341.  
  342.   /*
  343.       Build the internal ranking list
  344.   */
  345.   CreateRankings();
  346.  
  347.  
  348.   /*
  349.       Allow the user to make settings.
  350.   */
  351.   if ((BoardNr = GetSettings(user))  ==  -1)
  352.   { return(FALSE);
  353.   }
  354.  
  355. #ifdef DEBUG_PAIRINGS
  356.   printf("Setting results:\n");
  357.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  358.   { if (t->Opponent)
  359.     { printf("Player %s paired against %s.\n", t->Name, t->Opponent->Name);
  360.     }
  361.     else if (t->GFlags & GMFLAGSF_NOFIGHT)
  362.     { printf("One point bye: %s\n", t->Name);
  363.     }
  364.     else
  365.     { printf("Player %s not set\n", t->Name);
  366.     }
  367.   }
  368. #endif
  369.  
  370.   /*
  371.       get colour of player 1
  372.   */
  373.   flag = (RangeRand(2) == 0)  ?  GMFLAGSF_WHITE  :  0;
  374.  
  375.  
  376.  
  377.   /*
  378.       Count the number of players without opponent. Get the number of players
  379.       with minimal rating. Additionally setup the colors for set players.
  380.   */
  381.   NumFreePlayers = 0;
  382.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  383.   { if (t->Opponent == NULL  &&  (t->GFlags & GMFLAGSF_NOFIGHT) == 0)
  384.     { NumFreePlayers++;
  385.     }
  386.     else if (t->Opponent)
  387.     { if ((t->GFlags & GMFLAGSF_WHITE) == 0  &&
  388.       (t->Opponent->GFlags & GMFLAGSF_WHITE) == 0)
  389.       { t->GFlags = flag;
  390.     flag = GMFLAGSF_WHITE - flag;
  391.     t->Opponent->GFlags = flag;
  392.       }
  393. #ifdef DEBUG_PAIRINGS
  394.       printf("Game set: %s : %s (%d)\n",
  395.          flag ? t->Opponent->Name : t->Name,
  396.          flag ? t->Name : t->Opponent->Name, BoardNr);
  397.     }
  398.     else
  399.     { printf("One point bye set: %s\n", t->Name);
  400. #endif
  401.     }
  402.   }
  403.  
  404.  
  405.   /*
  406.       If the number of free players is odd, select a player which receives a
  407.       one point bye.
  408.   */
  409. #ifdef DEBUG_PAIRINGS
  410.   printf("Number of players not set: %d\n", NumFreePlayers);
  411. #endif
  412.   if (NumFreePlayers % 2)
  413.   { int i, ihelp;
  414.  
  415.     /*
  416.     Find the 5 players with the lowest ranking.
  417.     */
  418.     int MinPlayers = (NumFreePlayers > 5) ? 5 : NumFreePlayers;
  419.  
  420.     i = ihelp = NumFreePlayers;
  421.     t = thelp = RankingFirst;
  422.     for (t = thelp = RankingFirst;  t != NULL;  t = t->RankNext)
  423.     { if (t->Opponent == NULL)
  424.       { if (thelp->Opponent != NULL)
  425.     { thelp = t;
  426.       ihelp = i;
  427.     }
  428.     if (tdwz(t) < tdwz(thelp))
  429.     { if (i >= MinPlayers)
  430.       { thelp = t;
  431.         ihelp = i;
  432.       }
  433.     }
  434.     --i;
  435.       }
  436.     }
  437. #ifdef DEBUG_PAIRINGS
  438.     printf("Looking for one point bye beginning with %s.\n", thelp->Name);
  439. #endif
  440.  
  441.     /*
  442.     Now thelp points to the last ihelp players. Select one of them.
  443.     */
  444.     j = RangeRand(ihelp);
  445.  
  446.     while(j > 0  ||  thelp->Opponent)
  447.     { if (!thelp->Opponent)
  448.       { --j;
  449.       }
  450.       thelp = thelp->RankNext;
  451.     }
  452.  
  453. #ifdef DEBUG_PAIRINGS
  454.     printf("Player %s gets a one point bye.\n", thelp->Name);
  455. #endif
  456.     thelp->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  457.     --NumFreePlayers;
  458.   }
  459.  
  460.  
  461.  
  462.  
  463.  
  464.   /*
  465.       Do the other pairings. t points into the upper and thelp into the
  466.       lower half of the players.
  467.   */
  468.   if ((NumGames = NumFreePlayers/2))
  469.   { /*
  470.     Initialize thelp
  471.     */
  472.     thelp = RankingFirst;
  473.     for (i = NumGames;  i;  thelp = thelp->RankNext)
  474.     { if (thelp->Opponent == NULL  &&
  475.       (thelp->GFlags & GMFLAGSF_NOFIGHT)  ==  0)
  476.       { i--;
  477.       }
  478.     }
  479.  
  480.     for (t = RankingFirst, i = NumGames;  i;  --i)
  481.     {
  482. #ifdef DEBUG_PAIRINGS
  483.       printf("Looking for next game: Upper half player %s, lower half player %s\n",
  484.          t->Name, thelp->Name);
  485. #endif
  486.       /*
  487.       t and thelp must not point on free or set players!
  488.       */
  489.       while ((t->GFlags & GMFLAGSF_NOFIGHT)  !=  0   ||
  490.          t->Opponent != NULL)
  491.       { t = t->RankNext;
  492.       }
  493.       while ((thelp->GFlags & GMFLAGSF_NOFIGHT)  !=  0   ||
  494.          thelp->Opponent != NULL)
  495.       { thelp = thelp->RankNext;
  496.       }
  497.  
  498.       t->Opponent = thelp;
  499.       thelp->Opponent = t;
  500.       t->BoardNr = ++BoardNr;
  501.       thelp->BoardNr = BoardNr;
  502.       t->GFlags = flag;
  503.       flag = GMFLAGSF_WHITE - flag;
  504.       thelp->GFlags = flag;
  505. #ifdef DEBUG_PAIRINGS
  506.       printf("Pairing %s : %s (%d)\n",
  507.          flag ? thelp->Name : t->Name,
  508.          flag ? t->Name : thelp->Name, t->BoardNr);
  509. #endif
  510.       t = t->RankNext;
  511.       thelp = thelp->RankNext;
  512.     }
  513.   }
  514.  
  515.   return(TRUE);
  516. }
  517.  
  518.  
  519.  
  520. /*
  521.     GamePossible() checks, if two players may be paired.
  522. */
  523. int GamePossible(struct Player *t1, struct Player *t2)
  524.  
  525. { struct Game *g;
  526.  
  527. #ifdef DEBUG_PAIRINGS
  528.   printf("Trying players %s and %s:", t1->Name, t2->Name);
  529. #endif
  530.   if (t1 == t2  ||
  531.       (t1->HowMuchWhiteLast >= 2  &&  t2->HowMuchWhiteLast >= 2)  ||
  532.       (t1->HowMuchWhiteLast <= -2  &&  t2->HowMuchWhiteLast <= -2))
  533.   {
  534. #ifdef DEBUG_PAIRINGS
  535.     printf("Colors don't match.\n");
  536. #endif
  537.     return(FALSE);
  538.   }
  539.  
  540.   for (g = t1->First_Game;  g != NULL;  g = g->Next)
  541.   {
  542.     if (g->Opponent == t2)
  543.     {
  544. #ifdef DEBUG_PAIRINGS
  545.       printf("Paired already.\n");
  546. #endif
  547.       return(FALSE);
  548.     }
  549.   }
  550. #ifdef DEBUG_PAIRINGS
  551.   printf("Ok\n");
  552. #endif
  553.   return(TRUE);
  554. }
  555.  
  556.  
  557.  
  558.  
  559. /*
  560.     The DoGame() function looks for a game in the actual group.
  561.  
  562.     Inputs: g            - group in which should be looked
  563.         t            - player, who should get an opponent
  564.         BoardNr        - number of the first board that isn't used
  565.         MayChangeColors - number of allowed pairings in the same color
  566.                   group
  567.         MayGoUpperHalf  - number of allowed pairings in the same (upper
  568.                   or lower) half
  569.         MayGoDown        - number players that may be left (1, if the
  570.                   number of players in the group is odd)
  571.  
  572.     Results:  0 = No pairings possible, terminate
  573.           1 = Successfull finish, terminate
  574.          -1 = The lower groups could not be paired and this is a group
  575.           with an even number of players. Put one into the next!
  576. */
  577. static int DoGroup(struct Group *);
  578. static int DoGame(struct Group *g, struct Player *t,
  579.               int MayChangeColors, int MayGoUpperHalf, int MayGoDown)
  580.  
  581. { struct Player *tg, *thelp, *LowerHalf;
  582.   int result;
  583.   int IsLowerHalf, i;
  584.  
  585.   switch (g->NumMembers-g->NumAllocMembers)
  586.   { /*
  587.     Only one player left? Put him into the next group or give him
  588.     a point for free if there are no lower groups.
  589.     */
  590.     case 1:
  591.       /*
  592.       Look for free player
  593.       */
  594.       for (t = g->First;  t->Opponent != NULL;  t = t->LT_Succ)
  595.       {
  596.       }
  597.  
  598.       if (g->Next == NULL)
  599.       { if (t->Flags & TNFLAGSF_HADFREE)
  600.     { return(0);
  601.     }
  602.     t->GFlags |= GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  603.     return(1);
  604.       }
  605.  
  606.       if (t->Flags & TNFLAGSF_NOTDOWN)
  607.       { return (FALSE);
  608.       }
  609.       thelp = t->LT_Pred;
  610.       MyRemove(g, t);
  611.       MyEnqueue(g->Next, t);
  612.       if ((result = DoGroup(g->Next))  ==  FALSE)
  613.       /*
  614.       Remember, that it doesn't help to put this player into the next
  615.       group.
  616.       */
  617.       { t->Flags |= TNFLAGSF_NOTDOWN;
  618.       }
  619.       MyRemove(g->Next, t);
  620.       MyInsert(g, t, thelp);
  621.       return(result);
  622.  
  623.  
  624.     /*
  625.     Group finished? On to the next! If not successfull now, we need
  626.     to change the group!
  627.     */
  628.     case 0:
  629.       return((DoGroup(g->Next) == 0)  ?  -1  :  1);
  630.  
  631.  
  632.     /*
  633.     We still need to do some pairings in this group. Sigh!
  634.     */
  635.     default:
  636.       /*
  637.       Looking for a player without opponent.
  638.       */
  639.       while (t->Opponent != NULL)
  640.       { t = t->LT_Succ;
  641.       }
  642.  
  643.       /*
  644.       We must not look for opponents in the upper half, if this player
  645.       is from the lower half! So check, if he is.
  646.       */
  647.       IsLowerHalf = TRUE;
  648.       LowerHalf = g->First;
  649.       i = (g->NumMembers/2);
  650.       do
  651.       { if (LowerHalf == t)
  652.     { IsLowerHalf = FALSE;
  653.     }
  654.     LowerHalf = LowerHalf->LT_Succ;
  655.       }
  656.       while(--i);
  657.  
  658.  
  659.       /*
  660.       Try to get an opponent in the lower half with different colors.
  661.       */
  662.       for (tg = IsLowerHalf ? t->LT_Succ : LowerHalf;   tg != NULL;
  663.        tg = tg->LT_Succ)
  664.       { if (tg->Opponent == NULL  &&
  665.         t->HowMuchWhiteLast*tg->HowMuchWhiteLast <= 0  &&
  666.         GamePossible(t, tg))
  667.     { /*
  668.           Try this pairing
  669.       */
  670.       t->Opponent = tg;
  671.       tg->Opponent = t;
  672.       g->NumAllocMembers += 2;
  673.       /*
  674.           Check if the remaining players may get paired.
  675.       */
  676.       if ((result = DoGame(g, t->LT_Succ,
  677.                    MayChangeColors, MayGoUpperHalf, MayGoDown))
  678.               !=  0)
  679.       { return(result);
  680.       }
  681.       /*
  682.           They don't, so undo this pairing.
  683.       */
  684.       g->NumAllocMembers -= 2;
  685.       t->Opponent = tg->Opponent = NULL;
  686.     }
  687.       }
  688.  
  689.       /*
  690.       Looking for an opponent in the lower half without changing the
  691.       colors. (If it is allowed!)
  692.       */
  693.       if (MayChangeColors != 0)
  694.       { for (tg = IsLowerHalf ? t->LT_Succ : LowerHalf;   tg != NULL;
  695.          tg = tg->LT_Succ)
  696.     { if (tg->Opponent == NULL  &&
  697.           t->HowMuchWhiteLast*tg->HowMuchWhiteLast > 0  &&
  698.           GamePossible(t, tg))
  699.       { /*
  700.         Try this pairing
  701.         */
  702.         t->Opponent = tg;
  703.         tg->Opponent = t;
  704.         g->NumAllocMembers += 2;
  705.         /*
  706.         Check if the remaining players may get paired.
  707.         */
  708.         if ((result = DoGame(g, t->LT_Succ, MayChangeColors-1,
  709.                  MayGoUpperHalf, MayGoDown))
  710.             !=  0)
  711.         { return(result);
  712.         }
  713.         /*
  714.         They don't, so undo this pairing.
  715.         */
  716.         g->NumAllocMembers -= 2;
  717.         t->Opponent = tg->Opponent = NULL;
  718.       }
  719.     }
  720.       }
  721.  
  722.       /*
  723.       Looking for an opponent in the upper half with different colors.
  724.       (If it is allowed!)
  725.       */
  726.       if (MayGoUpperHalf != 0)
  727.       { for (tg = IsLowerHalf ? NULL : LowerHalf->LT_Pred;
  728.          tg != NULL  &&  tg != t;  tg = tg->LT_Pred)
  729.     { if(tg->Opponent == NULL  &&
  730.          t->HowMuchWhiteLast*tg->HowMuchWhiteLast <= 0  &&
  731.          GamePossible(t, tg))
  732.       { /*
  733.         Try this pairing
  734.         */
  735.         t->Opponent = tg;
  736.         tg->Opponent = t;
  737.         g->NumAllocMembers += 2;
  738.         /*
  739.         Check if the remaining players may get paired.
  740.         */
  741.         if ((result = DoGame(g, t->LT_Succ, MayChangeColors,
  742.                  MayGoUpperHalf-1, MayGoDown))
  743.             !=  0)
  744.         { return(result);
  745.         }
  746.         /*
  747.         They don't, so undo this pairing.
  748.         */
  749.         g->NumAllocMembers -= 2;
  750.         t->Opponent = tg->Opponent = NULL;
  751.       }
  752.     }
  753.       }
  754.  
  755.       /*
  756.       Finally looking for an opponent in the upper half without
  757.       changing colors. Do we really need this? Arrgl! (It would not be
  758.       allowed otherwise.)
  759.       */
  760.       if (MayChangeColors != 0  &&  MayGoUpperHalf != 0)
  761.       { for (tg = IsLowerHalf ? NULL : LowerHalf->LT_Pred;
  762.          tg != NULL  &&  tg != t;  tg = tg->LT_Pred)
  763.     { if(tg->Opponent == NULL  &&
  764.          t->HowMuchWhiteLast*tg->HowMuchWhiteLast > 0  &&
  765.          GamePossible(t, tg))
  766.       { /*
  767.         Try this pairing
  768.         */
  769.         t->Opponent = tg;
  770.         tg->Opponent = t;
  771.         g->NumAllocMembers += 2;
  772.         /*
  773.         Check if the remaining players may get paired.
  774.         */
  775.         if ((result = DoGame(g, t->LT_Succ, MayChangeColors-1,
  776.                  MayGoUpperHalf-1, MayGoDown))
  777.             !=  0)
  778.         { return(result);
  779.         }
  780.         /*
  781.         They don't, so undo this pairing.
  782.         */
  783.         g->NumAllocMembers -= 2;
  784.         t->Opponent = tg->Opponent = NULL;
  785.       }
  786.     }
  787.       }
  788.  
  789.       /*
  790.       The LAST possibility is to drop one player, who will finally
  791.       get moved into the next group.
  792.       */
  793.       if (MayGoDown)
  794.       { return(DoGame(g, t->LT_Succ, MayChangeColors,
  795.               MayGoUpperHalf, 0));
  796.       }
  797.     }
  798.  
  799.   /*
  800.       Nothing helps. We cannot pair the remaining members of this group.
  801.       Give up!
  802.   */
  803.   return(0);
  804. }
  805.  
  806.  
  807.  
  808.  
  809. /*
  810.     The DoGroup() function is the main function to do the Swiss pairing.
  811.     It pairs the member of one group of players (Usually the players with
  812.     the same number of points.) and calls itself for the next group, if
  813.     possible.
  814.  
  815.     Inputs: g        -    the group to pair
  816.  
  817.     Results: 1 = Success, finish!
  818.          0 = The group could not be paired, so the higher groups need
  819.          to be rearranged.
  820.  
  821.  
  822.     The algorithm depends on the rules from the "Turnierleiterhandbuch des
  823.     Deutschen Schachbundes" (The official german chess federation's guide
  824.     to managing chess-tournaments). But this rules aren't quite clear and
  825.     especially not definite. For example i don't see what should happen,
  826.     if some players with the same number of points are leading, but have
  827.     already been paired against each other.
  828.  
  829.     The pairing begins with collecting the players in groups of members
  830.     with the same number of points. These groups are used to build the new
  831.     internal ranking list. Players of one group are ordered by the previous
  832.     list and by the official lists in the first round. DoGroup() gets called
  833.     for the highest group, if successfull for the next group and so on.
  834.  
  835.     But how to pair the group-members? We begin with splitting the members
  836.     in an upper and a lower half. (The lower has possibly one member more,
  837.     if the number of group-members is odd.) Both halfs get splitted again,
  838.     depending on their last color. Example: (The players to the left had
  839.     white in the last round.)
  840.  
  841.         Upper Half:   1   3
  842.                   2
  843.         Lower Half:   4   5
  844.                   7   6
  845.  
  846.     DoGame() gets called to find an opponent for player 1. We try player 5
  847.     and next player 6. DoGame() calls itself for an opponent of player 2,
  848.     if successfull. If it is successfull again, it calls itself for the third
  849.     time, to find an opponent for player 3. When 3 games have been found,
  850.     this group is done and we move the remaining player into the next group
  851.     and call DoGroup() for it.
  852.  
  853.     But possibly it isn't possible to pair the players in that way. In that
  854.     case we need to allow some things that we don't like very much: Pairing
  855.     opponents of the same color (1-4), pairing opponents from the upper half
  856.     (1-3) or dropping players which will get moved into the next group
  857.     then. The variables MayChangeColors, MayGoUpperHalf and MayGoDown tell
  858.     us, what is allowed.
  859.  
  860.     A game is possible, if
  861.     a) The same players haven't already been paired
  862.     b) No opponent has the same color for the third time (However, it
  863.        is allowed to have four times black in 5 rounds! Not my choice,
  864.        i follow the guide mentioned above.)
  865.     c) the remaining players may be paired and a) and b) holds still
  866.        for them
  867. */
  868. static int DoGroup(struct Group *g)
  869.  
  870. { struct Player *t;
  871.   int result;
  872.   int MayChangeColors, MayGoUpperHalf, MayGoDown;
  873.  
  874. #ifdef DEBUG_PAIRINGS
  875.   /*
  876.       Print the list of group members.
  877.   */
  878.   { extern struct Group *FirstGroup;
  879.     struct Group *myg;
  880.     struct Player *myt;
  881.  
  882.     for (myg = FirstGroup;  myg != NULL;  myg = myg->Next)
  883.     { printf("(");
  884.       for(myt = myg->First;  myt != NULL;  myt = myt->LT_Succ)
  885.       { if (myt != myg->First)
  886.     { printf(",");
  887.     }
  888.     printf("%s", myt->Name);
  889.       }
  890.       printf(")");
  891.     }
  892.     printf("\n");
  893.   }
  894. #endif
  895.  
  896.   /*
  897.       Looking for a nonempty group (Not sure, if this might happen, but
  898.       does no harm!
  899.   */
  900.   while(g != NULL  &&  g->NumMembers == 0)
  901.   { g = g->Next;
  902.   }
  903.   if (g == NULL)
  904.   { return(1);
  905.   }
  906.  
  907.  
  908.   /*
  909.       Remove the TNFLAGSF_NOTDOWN flag from all group members. (They might
  910.       have received it sooner.)
  911.   */
  912.   for(t = g->First;  t != NULL;  t = t->LT_Succ)
  913.   { t->Flags &= ~TNFLAGSF_NOTDOWN;
  914.   }
  915.  
  916.   /*
  917.       We begin with allowing NOTHING and slowly a little bit more...
  918.       (I would be glad, if any body knew a faster solution!)
  919.   */
  920.   MayGoDown = 0;
  921.   do
  922.   { MayGoUpperHalf = 0;
  923.     do
  924.     { MayChangeColors = 0;
  925.       do
  926.       { switch (DoGame(g, g->First, MayChangeColors, MayGoUpperHalf,
  927.                MayGoDown))
  928.     { case 1:
  929.         /*
  930.         Success!
  931.         */
  932.         return(1);
  933.       case -1:
  934.         /*
  935.         The following groups cannot be paired! Senseless to pair this
  936.         group. Undo all pairings and change the group.
  937.         */
  938.         for (t = g->First;  t != NULL;  t = t->LT_Succ)
  939.         { t->Opponent = NULL;
  940.         }
  941.         g->NumAllocMembers = 0;
  942.         goto changegroup;
  943.     }
  944.       }
  945.       while (++MayChangeColors <= g->NumMembers/2);
  946.     }
  947.     while (++MayGoUpperHalf <= g->NumMembers/4);
  948.   }
  949.   while (++MayGoDown <= g->NumMembers % 2);
  950.  
  951. changegroup:
  952.   /*
  953.       It isn't possible, to pair this group. The last possibility is to
  954.       move one player into the next and retry. (DoGame() has already done
  955.       this, if there is only one member.)
  956.   */
  957.   if (g->Next != NULL  &&  g->NumMembers != 1)
  958.   { t = g->Last;
  959.     MyRemove(g, t);
  960.     MyEnqueue(g->Next, t);
  961.     result = DoGroup(g);
  962.     if (result)
  963.     { return(TRUE);
  964.     }
  965.     MyRemove(g->Next, t);
  966.     MyAddTail(g, t);
  967.   }
  968.  
  969.   /*
  970.       Doesn't help! We have failed!
  971.   */
  972.   return(FALSE);
  973. }
  974.  
  975.  
  976.  
  977.  
  978. /*
  979.     The DoSwissPairing() function gets called instead of
  980.     DoSwissPairingFirst() for round 2 and later.
  981.  
  982.     Inputs: user - TRUE, if the user may set games
  983.  
  984.     Result: TRUE, if succesfull, FALSE otherwise
  985. */
  986. #ifdef DEBUG_PAIRINGS
  987. struct Group *FirstGroup;
  988. #endif
  989. static int DoSwissPairing(int user)
  990.  
  991. { struct Player *t, *thelp, **tptr;
  992.   struct Group *g, **gptr;
  993.   void *PKey = NULL;
  994.   short gpoints;
  995.   int BoardNr;
  996.   int i, result;
  997. #ifndef DEBUG_PAIRINGS
  998.   struct Group *FirstGroup;
  999. #endif
  1000.  
  1001.   FirstGroup = NULL;
  1002.  
  1003.   /*
  1004.       First create the new ranking list
  1005.   */
  1006.   t = RankingFirst;
  1007.   RankingFirst = NULL;
  1008.   while (t != NULL)
  1009.   { for (tptr = &RankingFirst;  *tptr != NULL;
  1010.      tptr = &((*tptr)->RankNext))
  1011.     { if (t->Points > (*tptr)->Points)
  1012.       { break;
  1013.       }
  1014.     }
  1015.     thelp = t->RankNext;
  1016.     t->RankNext = *tptr;
  1017.     *tptr = t;
  1018.     t = thelp;
  1019.   }
  1020. #ifdef DEBUG_PAIRINGS
  1021.   { int i;
  1022.  
  1023.     printf("New rankings:\n");
  1024.     for (i = 1, t = RankingFirst;  t != NULL;  t = t->RankNext, ++i)
  1025.     { printf("%5d. %s\n", i, t->Name);
  1026.     }
  1027.   }
  1028. #endif
  1029.  
  1030.  
  1031.   /*
  1032.       Allow the user to make settings.
  1033.   */
  1034.   if ((BoardNr = GetSettings(user))  ==  -1)
  1035.   { return(FALSE);
  1036.   }
  1037.  
  1038.  
  1039.   /*
  1040.       Create the groups of players with the same number of points
  1041.   */
  1042.   gpoints = -1;   /*
  1043.               Force initialization of g and gpoints in the following
  1044.               loop.
  1045.           */
  1046.   gptr = &FirstGroup;
  1047.   i = 0;
  1048.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  1049.   { t->Nr = i++;
  1050.     if (t->Flags & TNFLAGSF_WITHDRAWN  ||  t->Opponent != NULL  ||
  1051.     t->GFlags & GMFLAGSF_NOFIGHT)
  1052.     { continue;
  1053.     }
  1054.     if (gpoints != t->Points)   /*  Create new group    */
  1055.     { if ((g = GetMem(&PKey, sizeof(*g)))  ==  NULL)
  1056.       { PutMemList(&PKey);
  1057.     return(FALSE);
  1058.       }
  1059.       *gptr = g;
  1060.       gptr = &(g->Next);
  1061.       gpoints = t->Points;
  1062.     }
  1063.  
  1064.     MyAddTail(g, t);
  1065.   }
  1066.  
  1067.  
  1068. #ifdef AMIGA
  1069.   set(App, MUIA_Application_Sleep, TRUE);
  1070. #endif
  1071.   result = DoGroup(FirstGroup);
  1072. #ifdef AMIGA
  1073.   set(App, MUIA_Application_Sleep, FALSE);
  1074. #endif
  1075.  
  1076.   if (!result)
  1077.   { ShowError((char *) GetChaosString(MSG_NO_PAIRING));
  1078.     PutMemList(&PKey);
  1079.     return(FALSE);
  1080.   }
  1081.  
  1082.   /*
  1083.       Select colors
  1084.   */
  1085.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  1086.   { if (t->Flags & TNFLAGSF_WITHDRAWN)
  1087.     { continue;
  1088.     }
  1089.     if (t->Opponent == NULL)
  1090.     { t->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  1091.     }
  1092.     else
  1093.     { /*
  1094.       Select colors
  1095.       */
  1096.       thelp = t->Opponent;
  1097.       if ((t->GFlags & GMFLAGSF_WHITE) == 0  &&
  1098.       (thelp->GFlags & GMFLAGSF_WHITE) == 0)
  1099.       { if (t->HowMuchWhiteLast < thelp->HowMuchWhiteLast  ||
  1100.         (t->HowMuchWhiteLast == thelp->HowMuchWhiteLast  &&
  1101.          (t->HowMuchWhite < thelp->HowMuchWhite  ||
  1102.           (t->HowMuchWhite == thelp->HowMuchWhite  &&
  1103.            t->Nr > thelp->Nr))))
  1104.     { thelp = t;
  1105.     }
  1106.     thelp->GFlags = GMFLAGSF_WHITE;
  1107.       }
  1108.     }
  1109.   }
  1110.   return(TRUE);
  1111. }
  1112.  
  1113.  
  1114.  
  1115.  
  1116. /*
  1117.     DoRoundRobin() does the Round Robin pairings. Here all rounds are paired
  1118.     at once.
  1119.  
  1120.     Inputs: mode - 0 for FIDE system, TNMODEF_SHIFT_SYSTEM for shift system
  1121.  
  1122.     Result: TRUE, if successfull, FALSE otherwise
  1123. */
  1124. static int DoRoundRobin(int mode)
  1125.  
  1126. { struct Player *t, **ttab, *tg;
  1127.   struct Group g;
  1128.   int i, j, k, l;
  1129.   int NumGames;
  1130.   int GamesMissing = 0;
  1131.   short flag, BoardNr;
  1132.   void *PMem = NULL, *GMem = NULL;
  1133.  
  1134.   /*
  1135.       Allocate a table of player numbers
  1136.   */
  1137.   if ((ttab = GetMem(&PMem, sizeof(*ttab)*NumPlayers))  ==  NULL)
  1138.   { return(FALSE);
  1139.   }
  1140.  
  1141.   /*
  1142.       Give any player a different number
  1143.   */
  1144.   g.First = g.Last = NULL;
  1145.   g.NumMembers = 0;
  1146.   for (t = (struct Player *) PlayerList.lh_Head;
  1147.        t->Tn_Node.ln_Succ != NULL;
  1148.        t = (struct Player *) t->Tn_Node.ln_Succ)
  1149.   { MyAddTail(&g, t);
  1150.   }
  1151.   while (g.NumMembers > 0)
  1152.   { i = RangeRand(g.NumMembers);
  1153.     for (t = g.First;  i > 0;  i--, t = t->LT_Succ)
  1154.     {
  1155.     }
  1156.     t->Nr = g.NumMembers;
  1157.     MyRemove(&g, t);
  1158.     ttab[g.NumMembers] = t;
  1159.   }
  1160.   NumGames = (NumPlayers+1)/2;
  1161.  
  1162.   if ((mode & TNMODEF_SHIFT_SYSTEM)  ==  0)
  1163.   { /*
  1164.     Here comes the FIDE-system.
  1165.  
  1166.     Assume n=NumPlayers (n=NumPlayers+1 for an odd number of players)
  1167.     The FIDE system wants the following pairings for round 1:
  1168.     1:n, 2:n-1, 3:n-2, 4:n-3 and so on. (n as opponent means free round,
  1169.     if the number of players is odd.)
  1170.     */
  1171.     for (i = 0;  i < NumGames; i++)
  1172.     { t = ttab[i];
  1173.       if(i == 0  &&  ((NumPlayers%2) != 0))    /*  Spielfrei   */
  1174.       { t->Opponent = NULL;
  1175.     t->BoardNr = i;
  1176.     t->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  1177.       }
  1178.       else
  1179.       { tg = ttab[NumGames*2-i-1];
  1180.  
  1181.     t->Opponent = tg;
  1182.     tg->Opponent = t;
  1183.     t->BoardNr = tg->BoardNr = i+1;
  1184.     t->GFlags = GMFLAGSF_WHITE;
  1185.     tg->GFlags = 0;
  1186.     GamesMissing++;
  1187.       }
  1188.     }
  1189.  
  1190.     if (!NewGames(&GMem, 0))
  1191.     { goto Error;
  1192.     }
  1193.  
  1194.     /*
  1195.     The following rounds are determined by a simple algorithm:
  1196.     (See Ernst Schubart, Helmut Noettger: "Turnierleiterhandbuch des
  1197.     Deutschen Schachbundes" (The official german chess federation's
  1198.     guide to managing chess-tournaments), p.64
  1199.  
  1200.     - In the odd rounds the players 1, 2, 3 and so on have player n as
  1201.       opponent (or have a free round, if the number of players is even.
  1202.       In the even rounds n plays against k+1, k+2, k+3 and so on, where
  1203.       k=n/2.
  1204.     - All other participants play against the player whose number is the
  1205.       number of their last opponent, incremented by 1. Player n is left
  1206.       out, player 1 comes after n-1.
  1207.     - If the number of players is even, the players 1, 2, ..., k have
  1208.       white, when playing against opponent n. The other players have
  1209.       black in that case.
  1210.     - In all other games the player with the lower number has the white
  1211.       pieces, if the sum of the two player-numbers is odd. Otherwise he
  1212.       gets the black pieces.
  1213.     */
  1214.     for (j = 1;  j < NumGames*2-1;  j++)
  1215.     { /*
  1216.       First get an opponent for player n.
  1217.       */
  1218.       k = (((j%2) == 0) ? 0 : NumGames) + j/2 + 1;
  1219.       t = ttab[k-1];
  1220.       if ((NumPlayers%2) == 0) /*  No point for free    */
  1221.       { tg = ttab[NumPlayers-1];
  1222.     t->BoardNr = tg->BoardNr = BoardNr = 0;
  1223.     t->GFlags = (t->Nr <= NumGames) ? GMFLAGSF_WHITE : 0;
  1224.     tg->GFlags = GMFLAGSF_WHITE - t->GFlags;
  1225.     tg->Opponent = t;
  1226.     GamesMissing++;
  1227.       }
  1228.       else
  1229.       { tg = NULL;
  1230.     t->BoardNr = BoardNr = -1;
  1231.     t->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  1232.       }
  1233.       t->Opponent = tg;
  1234.  
  1235.       /*
  1236.       Get the other games
  1237.       */
  1238.       for (i = 1;  i < NumGames;  i++)
  1239.       { if (++k == NumGames*2)
  1240.     { k = 1;
  1241.     }
  1242.     t = ttab[k-1];
  1243.     if ((tg = GameAddress(t, j)->Opponent) == NULL  ||
  1244.         tg->Nr == NumGames*2)
  1245.     { l = t->Nr;
  1246.     }
  1247.     else
  1248.     { l = tg->Nr;
  1249.     }
  1250.     if (++l == NumGames*2)
  1251.     { l = 1;
  1252.     }
  1253.     tg = ttab[l-1];
  1254.     flag = (((t->Nr+tg->Nr) % 2) != 0) ? GMFLAGSF_WHITE : 0;
  1255.     if (t->Nr > tg->Nr)
  1256.     { flag = GMFLAGSF_WHITE-flag;
  1257.     }
  1258.     t->GFlags = flag;
  1259.     tg->GFlags = GMFLAGSF_WHITE-flag;
  1260.     t->BoardNr = tg->BoardNr = ++BoardNr;
  1261.     t->Opponent = tg;
  1262.     tg->Opponent = t;
  1263.     GamesMissing++;
  1264.       }
  1265.  
  1266.       if (!NewGames(&GMem, 0))
  1267.       { goto Error;
  1268.       }
  1269.     }
  1270.   }
  1271.   else
  1272.   { /*
  1273.     Here comes the shift system. Its algorithm is rather easy, if you
  1274.     have seen it in practice.
  1275.  
  1276.     The boards are placed reverted on the table and all players sit down
  1277.     for the first round in the following order:
  1278.                 1 : k
  1279.                 2 : k+1
  1280.                 3 : k+2
  1281.                   .
  1282.                   .
  1283.                   .
  1284.               k-1 : n
  1285.     (We assume again, that n is the number of players is even and
  1286.     k = n/2. If this isn't true, we add a virtual player n. Playing
  1287.     against n means having a free game.)
  1288.  
  1289.     After each round the players 1, 2, 3, ..., n-1 are shifted clockwise.
  1290.     All boards remain unchanged, except for the board of player n, who
  1291.     may keep his place, but has to revert his board.
  1292.  
  1293.     Below the array ttab is used to simulate the table. (That's probably
  1294.     why it's got his name...)
  1295.     */
  1296.     int lastflag;
  1297.  
  1298.     for (i = 0;  i < NumGames*2-1;  i++)
  1299.     { for (j = 0, flag = GMFLAGSF_WHITE;  j < NumGames; j++)
  1300.       { t = ttab[j];
  1301.     if (j+NumGames < NumPlayers)
  1302.     { tg = ttab[j+NumGames];
  1303.       t->GFlags = flag;
  1304.       flag = GMFLAGSF_WHITE-flag;
  1305.       tg->GFlags = flag;
  1306.       tg->Opponent = t;
  1307.       tg->BoardNr = j+1;
  1308.     }
  1309.     else
  1310.     { tg = NULL;
  1311.     }
  1312.     t->Opponent = tg;
  1313.     t->BoardNr = j+1;
  1314.       }
  1315.       if (i == 0)
  1316.       { lastflag = flag;
  1317.       }
  1318.       else if (NumPlayers == NumGames*2)
  1319.       { t = ttab[NumGames-1];
  1320.     tg = ttab[NumGames*2-1];
  1321.     t->GFlags = lastflag;
  1322.     lastflag = GMFLAGSF_WHITE-lastflag;
  1323.     tg->GFlags = lastflag;
  1324.       }
  1325.     if (!NewGames(&GMem, 0))
  1326.     { goto Error;
  1327.     }
  1328.  
  1329.     /*
  1330.     Shift all players except for n.
  1331.     */
  1332.     t = ttab[0];
  1333.     for (j = 0;  j < NumGames-1;  j++)
  1334.     { ttab[j] = ttab[j+1];
  1335.     }
  1336.     ttab[NumGames-1] = ttab[NumGames*2-2];
  1337.     for (j = NumGames*2-3;  j >= NumGames;  j--)
  1338.     { ttab[j+1] = ttab[j];
  1339.     }
  1340.     ttab[NumGames] = t;
  1341.     }
  1342.   }
  1343.  
  1344.   PutMem(ttab);
  1345.   MoveMemList(&GMem, &TrnMem);
  1346.   NumGamesMissing = GamesMissing;
  1347.   return(TRUE);
  1348.  
  1349. Error:
  1350.   for (t = (struct Player *) PlayerList.lh_Head;
  1351.        t->Tn_Node.ln_Succ != NULL;
  1352.        t = (struct Player *) t->Tn_Node.ln_Succ)
  1353.   { t->First_Game = NULL;
  1354.   }
  1355.   PutMemList(&GMem);
  1356.   PutMem(ttab);
  1357.   NumRounds = 0;
  1358.   return(FALSE);
  1359. }
  1360.  
  1361.  
  1362.  
  1363.  
  1364. /*
  1365.     This function selects the boards, where the players should play.
  1366. */
  1367. static void SelectBoards(void)
  1368.  
  1369. { struct Player *p;
  1370.   int BoardNr;
  1371.  
  1372.   for (p = RankingFirst;  p != NULL;  p = p->RankNext)
  1373.   { p->BoardNr = -1;
  1374.   }
  1375.  
  1376.   for (p = RankingFirst, BoardNr = 0;  p != NULL;  p = p->RankNext)
  1377.   { if (p->BoardNr < 0  &&  p->Opponent != NULL)
  1378.     { p->BoardNr = p->Opponent->BoardNr = BoardNr++;
  1379.     }
  1380.   }
  1381. }
  1382.  
  1383.  
  1384.  
  1385.  
  1386.  
  1387. /*
  1388.     DoPairings() is the function that gets called from the menu.
  1389.  
  1390.     Input:  mode - tournament mode (TNMODEF_SWISS_PAIRING or
  1391.            TNMODEF_ROUND_ROBIN with or without TNMODEF_SHIFT_SYSTEM)
  1392.         save - TRUE, if the user should be asked to save the tournament
  1393.         user - TRUE, if the user may set games (ignored for Round
  1394.            Robin tournaments)
  1395.  
  1396.     Result: TRUE, if successfull, FALSE otherwise
  1397. */
  1398. int DoPairings(int mode, int save, int user)
  1399.  
  1400. { struct Player *t, *rankingfirst;
  1401.   char *name;
  1402.   char trnfilename[TRNFILENAME_LEN+1];
  1403.   char ending[20];
  1404.   int len, endlen, oldNumRounds = NumRounds;
  1405.  
  1406.   /*
  1407.       Copy the ranking pointers. This allows to undo the pairing calls, if
  1408.       something goes wrong. Additionally the Opponent and GFlags fields
  1409.       get initialized.
  1410.   */
  1411.   rankingfirst = RankingFirst;
  1412.   for (t = (struct Player *) PlayerList.lh_Head;
  1413.        t->Tn_Node.ln_Succ != NULL;
  1414.        t = (struct Player *) t->Tn_Node.ln_Succ)
  1415.   { t->Helpptr = t->RankNext;
  1416.     t->Opponent = NULL;
  1417.     t->GFlags = 0;
  1418.   }
  1419.  
  1420.   if (mode & TNMODEF_SWISS_PAIRING)
  1421.   { if (!((NumRounds == 0)  ?  DoSwissPairingFirst(user)  :
  1422.                    DoSwissPairing(user)))
  1423.     { goto Error;
  1424.     }
  1425.     SelectBoards();
  1426.     NewGames(&TrnMem, WinnerPoints);
  1427.   }
  1428.   else
  1429.   { if (!DoRoundRobin(mode))
  1430.     { goto Error;
  1431.     }
  1432.   }
  1433.   TrnMode |= mode;
  1434.   IsSaved = FALSE;
  1435.  
  1436.  
  1437.   /*
  1438.       Offer the user to save data. If the convention "name.roundnumber.cdat"
  1439.       was kept until now, we keep this.
  1440.   */
  1441.   if (save)
  1442.   { strcpy(trnfilename, TrnFileName);
  1443.     sprintf(ending, ".%d.cdat", oldNumRounds);
  1444.     endlen = strlen(ending);
  1445.     len = strlen(trnfilename);
  1446.     if (len >= endlen  &&
  1447.     Stricmp((STRPTR) trnfilename+(len-endlen), (STRPTR) ending)  ==  0)
  1448.     { sprintf(trnfilename+(len-endlen), ".%d.cdat", NumRounds);
  1449.     }
  1450.     name = FileRequest(trnfilename, NULL, NULL, TRUE);
  1451.     if (name  !=  NULL  &&  *name != '\0')
  1452.     { return(SaveTournament(name));
  1453.     }
  1454.   }
  1455.   return(TRUE);;
  1456.  
  1457. Error:
  1458.   /*
  1459.       Get the old ranking list
  1460.   */
  1461.   RankingFirst = rankingfirst;
  1462.   for (t = (struct Player *) PlayerList.lh_Head;
  1463.        t->Tn_Node.ln_Succ != NULL;
  1464.        t = (struct Player *) t->Tn_Node.ln_Succ)
  1465.   { t->RankNext = t->Helpptr;
  1466.   }
  1467.   return(FALSE);
  1468. }
  1469.